home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / Direct3D / BumpMapping / DotProduct3 / dotproduct3.cpp < prev    next >
C/C++ Source or Header  |  2001-10-31  |  18KB  |  536 lines

  1. //-----------------------------------------------------------------------------
  2. // File: DotProduct3.cpp
  3. //
  4. // Desc: D3D sample showing how to do bumpmapping using the DotProduct3 
  5. //       texture operation.
  6. // 
  7. // Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <tchar.h>
  11. #include <math.h>
  12. #include <stdio.h>
  13. #include <D3DX8.h>
  14. #include "D3DApp.h"
  15. #include "D3DFont.h"
  16. #include "D3DUtil.h"
  17. #include "DXUtil.h"
  18. #include "resource.h"
  19.  
  20.  
  21.  
  22.  
  23. //-----------------------------------------------------------------------------
  24. // Name: 
  25. // Desc: 
  26. //-----------------------------------------------------------------------------
  27. struct CUSTOMVERTEX
  28. {
  29.     D3DXVECTOR3 v;
  30.     DWORD       diffuse;
  31.     DWORD       specular;
  32.     FLOAT       tu, tv;
  33. };
  34.  
  35. #define CUSTOMVERTEX_FVF (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_SPECULAR|D3DFVF_TEX1)
  36.  
  37.  
  38.  
  39.  
  40. //-----------------------------------------------------------------------------
  41. // Name: class CMyD3DApplication
  42. // Desc: Application class. The base class (CD3DApplication) provides the 
  43. //       generic functionality needed in all Direct3D samples. CMyD3DApplication 
  44. //       adds functionality specific to this sample program.
  45. //-----------------------------------------------------------------------------
  46. class CMyD3DApplication : public CD3DApplication
  47. {
  48.     CD3DFont*          m_pFont;
  49.     CUSTOMVERTEX       m_QuadVertices[4];
  50.     LPDIRECT3DTEXTURE8 m_pCustomNormalMap;
  51.     LPDIRECT3DTEXTURE8 m_pFileBasedNormalMap;
  52.     D3DXVECTOR3        m_vLight;
  53.  
  54.     BOOL               m_bUseFileBasedTexture;
  55.     BOOL               m_bShowNormalMap;
  56.  
  57.     HRESULT CreateFileBasedNormalMap();
  58.     HRESULT CreateCustomNormalMap();
  59.     HRESULT ConfirmDevice( D3DCAPS8*, DWORD, D3DFORMAT );
  60.     LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  61.  
  62. protected:
  63.     HRESULT OneTimeSceneInit();
  64.     HRESULT InitDeviceObjects();
  65.     HRESULT RestoreDeviceObjects();
  66.     HRESULT InvalidateDeviceObjects();
  67.     HRESULT DeleteDeviceObjects();
  68.     HRESULT Render();
  69.     HRESULT FrameMove();
  70.     HRESULT FinalCleanup();
  71.  
  72. public:
  73.     CMyD3DApplication();
  74. };
  75.  
  76.  
  77.  
  78.  
  79. //-----------------------------------------------------------------------------
  80. // Name: WinMain()
  81. // Desc: Entry point to the program. Initializes everything, and goes into a
  82. //       message-processing loop. Idle time is used to render the scene.
  83. //-----------------------------------------------------------------------------
  84. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  85. {
  86.     CMyD3DApplication d3dApp;
  87.  
  88.     if( FAILED( d3dApp.Create( hInst ) ) )
  89.         return 0;
  90.  
  91.     return d3dApp.Run();
  92. }
  93.  
  94.  
  95.  
  96.  
  97. //-----------------------------------------------------------------------------
  98. // Name: VectortoRGBA()
  99. // Desc: Turns a normalized vector into RGBA form. Used to encode vectors into
  100. //       a height map. 
  101. //-----------------------------------------------------------------------------
  102. DWORD VectortoRGBA( D3DXVECTOR3* v, FLOAT fHeight )
  103. {
  104.     DWORD r = (DWORD)( 127.0f * v->x + 128.0f );
  105.     DWORD g = (DWORD)( 127.0f * v->y + 128.0f );
  106.     DWORD b = (DWORD)( 127.0f * v->z + 128.0f );
  107.     DWORD a = (DWORD)( 255.0f * fHeight );
  108.     
  109.     return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) );
  110. }
  111.  
  112.  
  113.  
  114.  
  115. //-----------------------------------------------------------------------------
  116. // Name: InitVertex()
  117. // Desc: Initializes a vertex
  118. //-----------------------------------------------------------------------------
  119. VOID InitVertex( CUSTOMVERTEX* vtx, FLOAT x, FLOAT y, FLOAT z, FLOAT tu, FLOAT tv )
  120. {
  121.     D3DXVECTOR3 v(1,1,1);
  122.     D3DXVec3Normalize( &v, &v );
  123.     vtx[0].v        = D3DXVECTOR3( x, y, z );
  124.     vtx[0].diffuse  = VectortoRGBA( &v, 1.0f );
  125.     vtx[0].specular = 0x40400000;
  126.     vtx[0].tu       = tu;
  127.     vtx[0].tv       = tv;
  128. }
  129.     
  130.  
  131.  
  132.  
  133. //-----------------------------------------------------------------------------
  134. // Name: CMyD3DApplication()
  135. // Desc: Application constructor. Sets attributes for the app.
  136. //-----------------------------------------------------------------------------
  137. CMyD3DApplication::CMyD3DApplication()
  138. {
  139.     m_strWindowTitle  = _T("DotProduct3: BumpMapping Technique");
  140.     m_bUseDepthBuffer = FALSE;
  141.  
  142.     m_pFont                = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  143.  
  144.     m_bUseFileBasedTexture = FALSE;
  145.     m_bShowNormalMap       = FALSE;
  146.  
  147.     m_pCustomNormalMap     = NULL;
  148.     m_pFileBasedNormalMap  = NULL;
  149. }
  150.  
  151.  
  152.  
  153.  
  154. //-----------------------------------------------------------------------------
  155. // Name: OneTimeSceneInit()
  156. // Desc: Called during initial app startup, this function performs all the
  157. //       permanent initialization.
  158. //-----------------------------------------------------------------------------
  159. HRESULT CMyD3DApplication::OneTimeSceneInit()
  160. {
  161.     InitVertex( &m_QuadVertices[0],-1.0f,-1.0f,-1.0f, 0.0f, 0.0f );
  162.     InitVertex( &m_QuadVertices[1], 1.0f,-1.0f,-1.0f, 1.0f, 0.0f );
  163.     InitVertex( &m_QuadVertices[2],-1.0f, 1.0f,-1.0f, 0.0f, 1.0f );
  164.     InitVertex( &m_QuadVertices[3], 1.0f, 1.0f,-1.0f, 1.0f, 1.0f );
  165.  
  166.     m_vLight = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  167.  
  168.     return S_OK;
  169. }
  170.  
  171.  
  172.  
  173.  
  174. //-----------------------------------------------------------------------------
  175. // Name: FrameMove()
  176. // Desc: Called once per frame, the call is the entry point for animating
  177. //       the scene.
  178. //-----------------------------------------------------------------------------
  179. HRESULT CMyD3DApplication::FrameMove()
  180. {
  181.     // Compute the light vector from the cursor position
  182.     if( GetFocus() )
  183.     {
  184.         POINT pt;
  185.         GetCursorPos( &pt );
  186.         ScreenToClient( m_hWnd, &pt );
  187.  
  188.         m_vLight.x = -( ( ( 2.0f * pt.x ) / m_d3dsdBackBuffer.Width ) - 1 );
  189.         m_vLight.y = -( ( ( 2.0f * pt.y ) / m_d3dsdBackBuffer.Height ) - 1 );
  190.         m_vLight.z = 0.0f;
  191.  
  192.         if( D3DXVec3Length( &m_vLight ) > 1.0f )
  193.             D3DXVec3Normalize( &m_vLight, &m_vLight );
  194.         else
  195.             m_vLight.z = sqrtf( 1.0f - m_vLight.x*m_vLight.x
  196.                                      - m_vLight.y*m_vLight.y );
  197.     }
  198.  
  199.     return S_OK;
  200. }
  201.  
  202.  
  203.  
  204.  
  205. //-----------------------------------------------------------------------------
  206. // Name: Render()
  207. // Desc: Called once per frame, the call is the entry point for 3d
  208. //       rendering. This function sets up render states, clears the
  209. //       viewport, and renders the scene.
  210. //-----------------------------------------------------------------------------
  211. HRESULT CMyD3DApplication::Render()
  212. {
  213.     // Clear the render target
  214.     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0x00000000f, 1.0f, 0L );
  215.  
  216.     // Begin the scene
  217.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  218.     {
  219.         // Store the light vector, so it can be referenced in D3DTA_TFACTOR
  220.         DWORD dwFactor = VectortoRGBA( &m_vLight, 0.0f );
  221.         m_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, dwFactor );
  222.  
  223.         // Modulate the texture (the normal map) with the light vector (stored
  224.         // above in the texture factor)
  225.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  226.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_DOTPRODUCT3 );
  227.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR );
  228.  
  229.         // If user wants to see the normal map, override the above renderstates and
  230.         // simply show the texture
  231.         if( TRUE == m_bShowNormalMap )
  232.             m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
  233.  
  234.         // Select which normal map to use
  235.         if( m_bUseFileBasedTexture )
  236.             m_pd3dDevice->SetTexture( 0, m_pFileBasedNormalMap );
  237.         else
  238.             m_pd3dDevice->SetTexture( 0, m_pCustomNormalMap );
  239.  
  240.         // Draw the bumpmapped quad
  241.         m_pd3dDevice->SetVertexShader( CUSTOMVERTEX_FVF );
  242.         m_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, m_QuadVertices, 
  243.                                        sizeof(CUSTOMVERTEX) );
  244.  
  245.         // Output statistics
  246.         m_pFont->DrawText( 2,  0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
  247.         m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
  248.  
  249.         // End the scene.
  250.         m_pd3dDevice->EndScene();
  251.     }
  252.  
  253.     return S_OK;
  254. }
  255.  
  256.  
  257.  
  258.  
  259.  
  260. //-----------------------------------------------------------------------------
  261. // Name: 
  262. // Desc: 
  263. //-----------------------------------------------------------------------------
  264. HRESULT CMyD3DApplication::CreateFileBasedNormalMap()
  265. {
  266.     HRESULT hr;
  267.  
  268.     // Load the texture from a file
  269.     if( FAILED( hr = D3DUtil_CreateTexture( m_pd3dDevice, _T("EarthBump.bmp"), 
  270.                                             &m_pFileBasedNormalMap, 
  271.                                             D3DFMT_A8R8G8B8 ) ) )
  272.         return D3DAPPERR_MEDIANOTFOUND;
  273.  
  274.     // Lock the texture
  275.     D3DLOCKED_RECT  d3dlr;
  276.     D3DSURFACE_DESC d3dsd;
  277.     m_pFileBasedNormalMap->GetLevelDesc( 0, &d3dsd );
  278.     m_pFileBasedNormalMap->LockRect( 0, &d3dlr, 0, 0 );
  279.     DWORD* pPixel = (DWORD*)d3dlr.pBits;
  280.  
  281.     // For each pixel, generate a vector normal that represents the change
  282.     // in thea height field at that pixel
  283.     for( DWORD j=0; j<d3dsd.Height; j++  )
  284.     {
  285.         for( DWORD i=0; i<d3dsd.Width; i++ )
  286.         {
  287.             DWORD color00 = pPixel[0];
  288.             DWORD color10 = pPixel[1];
  289.             DWORD color01 = pPixel[d3dlr.Pitch/sizeof(DWORD)];
  290.  
  291.             FLOAT fHeight00 = (FLOAT)((color00&0x00ff0000)>>16)/255.0f;
  292.             FLOAT fHeight10 = (FLOAT)((color10&0x00ff0000)>>16)/255.0f;
  293.             FLOAT fHeight01 = (FLOAT)((color01&0x00ff0000)>>16)/255.0f;
  294.  
  295.             D3DXVECTOR3 vPoint00( i+0.0f, j+0.0f, fHeight00 );
  296.             D3DXVECTOR3 vPoint10( i+1.0f, j+0.0f, fHeight10 );
  297.             D3DXVECTOR3 vPoint01( i+0.0f, j+1.0f, fHeight01 );
  298.             D3DXVECTOR3 v10 = vPoint10 - vPoint00;
  299.             D3DXVECTOR3 v01 = vPoint01 - vPoint00;
  300.  
  301.             D3DXVECTOR3 vNormal;
  302.             D3DXVec3Cross( &vNormal, &v10, &v01 );
  303.             D3DXVec3Normalize( &vNormal, &vNormal );
  304.  
  305.             // Store the normal as an RGBA value in the normal map
  306.             *pPixel++ = VectortoRGBA( &vNormal, fHeight00 );
  307.         }
  308.     }
  309.  
  310.     // Unlock the texture and return successful
  311.     m_pFileBasedNormalMap->UnlockRect(0);
  312.  
  313.     return S_OK;
  314. }
  315.  
  316.  
  317.  
  318.  
  319. //-----------------------------------------------------------------------------
  320. // Name: 
  321. // Desc: 
  322. //-----------------------------------------------------------------------------
  323. HRESULT CMyD3DApplication::CreateCustomNormalMap()
  324. {
  325.     DWORD   dwWidth  = 512;
  326.     DWORD   dwHeight = 512;
  327.     HRESULT hr;
  328.  
  329.     // Create a 32-bit texture for the custom normal map
  330.     hr = m_pd3dDevice->CreateTexture( dwWidth, dwHeight, 1, 
  331.                                       0 /* Usage */, 
  332.                                       D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, 
  333.                                       &m_pCustomNormalMap );
  334.     if( FAILED(hr) )
  335.         return hr;
  336.  
  337.     // Lock the texture to fill it with our custom image
  338.     D3DLOCKED_RECT d3dlr;
  339.     if( FAILED( m_pCustomNormalMap->LockRect( 0, &d3dlr, 0, 0 ) ) )
  340.         return E_FAIL;
  341.     DWORD* pPixel = (DWORD*)d3dlr.pBits;
  342.  
  343.     // Fill each pixel
  344.     for( DWORD j=0; j<dwHeight; j++  )
  345.     {
  346.         for( DWORD i=0; i<dwWidth; i++ )
  347.         {
  348.             FLOAT xp = ( (5.0f*i) / (dwWidth-1)  );
  349.             FLOAT yp = ( (5.0f*j) / (dwHeight-1) );
  350.             FLOAT x  = 2*(xp-floorf(xp))-1;
  351.             FLOAT y  = 2*(yp-floorf(yp))-1;
  352.             FLOAT z  = sqrtf( 1.0f - x*x - y*y );
  353.  
  354.             // Make image of raised circle. Outside of circle is gray
  355.             if( (x*x + y*y) <= 1.0f )
  356.             {
  357.                 D3DXVECTOR3 vVector( x, y, z );
  358.                 *pPixel++ = VectortoRGBA( &vVector, 1.0f );
  359.             }
  360.             else
  361.                 *pPixel++ = 0x80808080;
  362.         }
  363.     }
  364.  
  365.     // Unlock the map and return successful
  366.     m_pCustomNormalMap->UnlockRect(0);
  367.  
  368.     return S_OK;
  369. }
  370.  
  371.  
  372.  
  373.  
  374. //-----------------------------------------------------------------------------
  375. // Name: InitDeviceObjects()
  376. // Desc: Initialize scene objects.
  377. //-----------------------------------------------------------------------------
  378. HRESULT CMyD3DApplication::InitDeviceObjects()
  379. {
  380.     HRESULT hr;
  381.  
  382.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  383.  
  384.     // Create the normal maps
  385.     if( FAILED( hr = CreateFileBasedNormalMap() ) )
  386.         return hr;
  387.     if( FAILED( hr = CreateCustomNormalMap() ) )
  388.         return hr;
  389.  
  390.     // Set menu states
  391.     CheckMenuItem( GetMenu(m_hWnd), IDM_USEFILEBASEDTEXTURE,
  392.                    m_bUseFileBasedTexture ? MF_CHECKED : MF_UNCHECKED );
  393.     CheckMenuItem( GetMenu(m_hWnd), IDM_USECUSTOMTEXTURE,
  394.                    m_bUseFileBasedTexture ? MF_UNCHECKED : MF_CHECKED );
  395.     CheckMenuItem( GetMenu(m_hWnd), IDM_SHOWNORMALMAP,    
  396.                    m_bShowNormalMap ? MF_CHECKED : MF_UNCHECKED );
  397.  
  398.     return S_OK;
  399. }
  400.  
  401.  
  402.  
  403.  
  404. //-----------------------------------------------------------------------------
  405. // Name: RestoreDeviceObjects()
  406. // Desc: Initialize scene objects.
  407. //-----------------------------------------------------------------------------
  408. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  409. {
  410.     m_pFont->RestoreDeviceObjects();
  411.  
  412.     // Set the transform matrices
  413.     D3DXVECTOR3 vEyePt    = D3DXVECTOR3( 0.0f, 0.0f, 2.0f );
  414.     D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  415.     D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  416.     D3DXMATRIX  matWorld, matView, matProj;
  417.     
  418.     D3DXMatrixIdentity( &matWorld );
  419.     D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
  420.     FLOAT fAspect = m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height;
  421.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 500.0f );
  422.     
  423.     m_pd3dDevice->SetTransform( D3DTS_WORLD,      &matWorld );
  424.     m_pd3dDevice->SetTransform( D3DTS_VIEW,       &matView );
  425.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  426.     
  427.     // Set misc render states
  428.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  429.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  430.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
  431.  
  432.     return S_OK;
  433. }
  434.  
  435.  
  436.  
  437.  
  438. //-----------------------------------------------------------------------------
  439. // Name: InvalidateDeviceObjects()
  440. // Desc: Called when the app is exiting, or the device is being changed,
  441. //       this function deletes any device dependent objects.
  442. //-----------------------------------------------------------------------------
  443. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  444. {
  445.     m_pFont->InvalidateDeviceObjects();
  446.     return S_OK;
  447. }
  448.  
  449.  
  450.  
  451.  
  452. //-----------------------------------------------------------------------------
  453. // Name: DeleteDeviceObjects()
  454. // Desc: Called when the app is exiting, or the device is being changed,
  455. //       this function deletes any device dependent objects.
  456. //-----------------------------------------------------------------------------
  457. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  458. {
  459.     m_pFont->DeleteDeviceObjects();
  460.     SAFE_RELEASE( m_pFileBasedNormalMap );
  461.     SAFE_RELEASE( m_pCustomNormalMap );
  462.  
  463.     return S_OK;
  464. }
  465.  
  466.  
  467.  
  468.  
  469. //-----------------------------------------------------------------------------
  470. // Name: FinalCleanup()
  471. // Desc: Called before the app exits, this function gives the app the chance
  472. //       to cleanup after itself.
  473. //-----------------------------------------------------------------------------
  474. HRESULT CMyD3DApplication::FinalCleanup()
  475. {
  476.     SAFE_DELETE( m_pFont );
  477.     return S_OK;
  478. }
  479.  
  480.  
  481.  
  482.  
  483. //-----------------------------------------------------------------------------
  484. // Name: ConfirmDevice()
  485. // Desc: Called during device intialization, this code checks the device
  486. //       for some minimum set of capabilities
  487. //-----------------------------------------------------------------------------
  488. HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior, 
  489.                                           D3DFORMAT Format )
  490. {
  491.     if( pCaps->TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3 )
  492.         return S_OK;
  493.     
  494.     return E_FAIL;
  495. }
  496.  
  497.  
  498.  
  499.  
  500. //-----------------------------------------------------------------------------
  501. // Name: MsgProc()
  502. // Desc: Message proc function to handle key and menu input
  503. //-----------------------------------------------------------------------------
  504. LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  505.                                     LPARAM lParam )
  506. {
  507.     if( uMsg == WM_COMMAND )
  508.     {
  509.         switch( LOWORD(wParam) )
  510.         {
  511.             case IDM_USEFILEBASEDTEXTURE:
  512.                 m_bUseFileBasedTexture = TRUE;
  513.                 CheckMenuItem( GetMenu(hWnd), IDM_USEFILEBASEDTEXTURE, MF_CHECKED );
  514.                 CheckMenuItem( GetMenu(hWnd), IDM_USECUSTOMTEXTURE,    MF_UNCHECKED );
  515.                 break;
  516.             
  517.             case IDM_USECUSTOMTEXTURE:
  518.                 m_bUseFileBasedTexture = FALSE;
  519.                 CheckMenuItem( GetMenu(hWnd), IDM_USEFILEBASEDTEXTURE, MF_UNCHECKED );
  520.                 CheckMenuItem( GetMenu(hWnd), IDM_USECUSTOMTEXTURE,    MF_CHECKED );
  521.                 break;
  522.             
  523.             case IDM_SHOWNORMALMAP:
  524.                 m_bShowNormalMap = !m_bShowNormalMap;
  525.                 CheckMenuItem( GetMenu(hWnd), IDM_SHOWNORMALMAP,    
  526.                                m_bShowNormalMap ? MF_CHECKED : MF_UNCHECKED );
  527.                 break;
  528.         }
  529.     }
  530.  
  531.     return CD3DApplication::MsgProc( hWnd, uMsg, wParam, lParam );
  532. }
  533.  
  534.  
  535.  
  536.